package com.zx.练习题._2022面试题;

import cn.hutool.core.date.DateUtil;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class 时间轮 {

    public static void main(String[] args) {
        TimeWheel.addTask(DateUtil.parse("2025-03-28 13:34:01", "yyyy-MM-dd HH:mm:ss"), "任务1");
        TimeWheel.addTask(DateUtil.parse("2025-03-28 13:34:02", "yyyy-MM-dd HH:mm:ss"), "任务2");
        TimeWheel.addTask(DateUtil.parse("2025-03-28 13:34:02", "yyyy-MM-dd HH:mm:ss"), "任务3");
    }

    private static class TimeWheel {

        private static final List<LinkedList<TimeTask>> wheel = new ArrayList<>();
        private static final ExecutorService pool = Executors.newFixedThreadPool(10);

        static {
            for (int i = 0; i < 60; i++) {
                wheel.add(new LinkedList<>());
            }

            long curMil = System.currentTimeMillis();
            long curSec = System.currentTimeMillis() / 1000;
            long nextMil = (curSec + 1) * 1000;
            int delayMil = (int) (nextMil - curMil);

            log.info("初始化时间轮, curMil={}, nextMil={}, delayMil={}", curMil, nextMil, delayMil);
            // 开启线程执行任务
            ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
            executor.scheduleAtFixedRate(TimeWheel::execute, delayMil, 1000, TimeUnit.MILLISECONDS);
        }

        // 添加任务
        public static void addTask(Date date, String taskName) {
            long time = date.getTime();
            long second = time / 1000;
            int idx = (int) (second % 60);
            log.info("提交任务, taskName={}, idx={}, time={}", taskName, idx, second);
            wheel.get(idx).add(new TimeTask(second, taskName));
        }

        //执行任务
        public static void execute() {
            long second = System.currentTimeMillis() / 1000;
            int idx = (int) (second % 60);
            log.info("执行任务, idx={}, second={}", idx, second);

            LinkedList<TimeTask> tasks = wheel.get(idx);
            if (tasks == null || tasks.isEmpty()) {
                log.info("执行任务, idx={}, second={}, 没有任务可以执行", idx, second);
                return;
            }

            // 可执行列表
            List<TimeTask> runs = tasks.stream().filter(t -> t.getTaskTime() <= second).collect(Collectors.toList());
            log.info("执行任务, idx={}, second={}, 发现任务数量={}", idx, second, runs.size());
            // 模拟提交任务到线程池执行任务
            for (TimeTask task : runs) {
                pool.execute(() -> {
                    tasks.remove(task);
                    log.info("执行任务, idx={}, second={}, 执行任务={}", idx, second, task.taskName);
                });
            }
        }


    }

    /**
     * 定时任务
     */
    @Data
    @AllArgsConstructor
    private static class TimeTask {

        //执行任务的时间点[记录秒]
        private long taskTime;
        //任务名称
        private String taskName;
    }

}
